﻿/**
 * Create in 2012-3-30.
 */
package kit4j.ui.cs.awt.image.drawer;

import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Map;

import kit4j.common.converter.Converter;
import kit4j.ui.cs.awt.image.ImageToBufferedImageConverter;

/**
 * 
 * @author MiniKnife
 * 
 */
public abstract class Abstract2DDrawer extends AbstractDrawer {

	private Converter<Image, BufferedImage> imageConverter;

	@Override
	protected Graphics2D getGraphics(Image img) {
		BufferedImage bufImg = convertImageToBufferedImage(img);
		Graphics2D g = bufImg.createGraphics();
		Color nextColor = nextColor(g);
		Font nextFont = nextFont(g);
		Color nextXORColor = nextXORColor(g);
		Color nextBackgroundColor = nextBackgroundColor(g);
		Composite nextComposite = nextComposite(g);
		Paint nextPaint = nextPaint(g);
		Map<?, ?> nextRenderingHints = nextRenderingHints(g);
		Stroke nextStroke = nextStroke(g);
		AffineTransform nextAffineTransform = nextAffineTransform(g);

		if (nextColor != null) {
			g.setColor(nextColor);
		}
		if (nextFont != null) {
			g.setFont(nextFont);
		}
		if (nextXORColor != null) {
			g.setXORMode(nextXORColor);
		}
		if (isPaintMode(g)) {
			g.setPaintMode();
		}
		if (nextBackgroundColor != null) {
			g.setBackground(nextBackgroundColor);
		}
		if (nextComposite != null) {
			g.setComposite(nextComposite);
		}
		if (nextPaint != null) {
			g.setPaint(nextPaint);
		}
		if (nextRenderingHints != null) {
			g.setRenderingHints(nextRenderingHints);
		}
		if (nextStroke != null) {
			g.setStroke(nextStroke);
		}
		if (nextAffineTransform != null) {
			g.setTransform(nextAffineTransform);
		}

		return g;
	}

	/**
	 * 将Image对象转换为BufferedImage对象。
	 * 
	 * @param img
	 *            要转换的Image对象
	 * @return 转换后的BufferedImage对象
	 */
	private BufferedImage convertImageToBufferedImage(Image img) {
		if (img instanceof BufferedImage) {
			return (BufferedImage) img;
		} else {
			Converter<Image, BufferedImage> converter = getImageConverter();

			return converter.convert(img);
		}
	}

	/**
	 * 返回图像类型转换器。
	 * 
	 * @return 图像类型转换器
	 */
	private Converter<Image, BufferedImage> getImageConverter() {
		if (imageConverter == null) {
			imageConverter = new ImageToBufferedImageConverter();
		}

		return imageConverter;
	}

	/**
	 * @see kit4j.ui.cs.awt.image.drawer.AbstractDrawer#nextColor(java.awt.Graphics)
	 */
	@Override
	protected Color nextColor(Graphics g) {
		return nextColor((Graphics2D) g);
	}

	/**
	 * @see kit4j.ui.cs.awt.image.drawer.AbstractDrawer#nextFont(java.awt.Graphics)
	 */
	@Override
	protected Font nextFont(Graphics g) {
		return nextFont((Graphics2D) g);
	}

	/**
	 * @see kit4j.ui.cs.awt.image.drawer.AbstractDrawer#nextXORColor(java.awt.Graphics)
	 */
	@Override
	protected Color nextXORColor(Graphics g) {
		return nextXORColor((Graphics2D) g);
	}

	/**
	 * @see kit4j.ui.cs.awt.image.drawer.AbstractDrawer#isPaintMode(java.awt.Graphics)
	 */
	@Override
	protected boolean isPaintMode(Graphics g) {
		return isPaintMode((Graphics2D) g);
	}

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的颜色。
	 * @see java.awt.Graphics2D#setColor(Color)
	 */
	abstract protected Color nextColor(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的字体。
	 * @see java.awt.Graphics2D#setFont(Font)
	 */
	abstract protected Font nextFont(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的XOR绘图模式颜色，如果不要设置，则返回null。
	 * @see java.awt.Graphics2D#setXORMode(Color)
	 */
	abstract protected Color nextXORColor(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 如果要将Graphics2D上下文设置为绘图模式，返回true，否则返回false。
	 * @see java.awt.Graphics2D#setPaintMode()
	 */
	protected boolean isPaintMode(Graphics2D g) {
		return false;
	}

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的背景色
	 * @see java.awt.Graphics2D#setBackground(Color)
	 */
	abstract protected Color nextBackgroundColor(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的Composite
	 * @see java.awt.Graphics2D#setComposite(Composite)
	 */
	abstract protected Composite nextComposite(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的Paint属性
	 * @see java.awt.Graphics2D#setPaint(Paint)
	 */
	abstract protected Paint nextPaint(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的呈现算法的首选项值
	 * @see java.awt.Graphics2D#setRenderingHint(Map)
	 */
	abstract protected RenderingHints nextRenderingHints(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的Stroke属性
	 * @see java.awt.Graphics2D#setStroke(Stroke)
	 */
	abstract protected Stroke nextStroke(Graphics2D g);

	/**
	 * @param g
	 *            要进行绘制的Graphics2D上下文
	 * @return 下一个要绘制的Graphics2D上下文的Transform
	 * @see java.awt.Graphics2D#setTransform(AffineTransform)
	 */
	abstract protected AffineTransform nextAffineTransform(Graphics2D g);

	/**
	 * @see kit4j.ui.cs.awt.image.drawer.AbstractDrawer#doDraw(java.awt.Image, java.awt.Graphics)
	 */
	@Override
	protected Image doDraw(Image img, Graphics g) {
		return doDraw(img, (Graphics2D) g);
	}

	/**
	 * 针对指定的图像在指定的Graphics2D上下文中进行绘制操作。
	 * 
	 * @param img
	 *            要进行绘制的图像
	 * @param g
	 *            进行绘制操作的Graphics2D上下文
	 * @return 绘制完成后的图像
	 */
	abstract protected Image doDraw(Image img, Graphics2D g);

}
